#include "C_gl_Buffer.h"

//////////////////////////////////////////////////////////////////////////
/// GL low level include
//////////////////////////////////////////////////////////////////////////
#include "../glCommon/glBuffer.h"
#include "../glCommon/glError.h"

#include <string.h>

C_gl_Buffer::C_gl_Buffer(const S_api_BufferDesc *pDesc, const S_api_Subresource_Data *pInitialData, const I_api_Device * pDevice) :
	I_api_Buffer(pDesc, pInitialData, pDevice)
{
	GL_BUFFER_DESC bufferdesc;
	bufferdesc.BindFlags = 0;

	if (pDesc->BindFlags & E_api_Bind_Constant_Buffer)
		bufferdesc.BindFlags = GL_BIND_CONSTANT_BUFFER;
		
	if (pDesc->BindFlags & E_api_Bind_Stream_Output)
		bufferdesc.BindFlags = GL_BIND_STREAM_OUTPUT;

	if (pDesc->BindFlags & E_api_Bind_Render_Target)
		bufferdesc.BindFlags = GL_BIND_RENDER_TARGET;

	if (pDesc->BindFlags & E_api_Bind_Shader_Resource)
		bufferdesc.BindFlags = GL_BIND_SHADER_RESOURCE;

	if (pDesc->BindFlags & E_api_Bind_Index_Buffer)
		bufferdesc.BindFlags = GL_BIND_INDEX_BUFFER;

	if (pDesc->BindFlags & E_api_Bind_Vertex_Buffer)
		bufferdesc.BindFlags = GL_BIND_VERTEX_BUFFER;		

	bufferdesc.ByteWidth = pDesc->ByteWidth;

	bufferdesc.CPUAccessFlags = pDesc->CPUAccessFlags;
	bufferdesc.MiscFlags = pDesc->MiscFlags;

	switch(pDesc->Usage)
	{
	case E_api_Usage_Default:
		bufferdesc.Usage = GL_USAGE_DEFAULT;
		break;
	case E_api_Usage_Immutable:
		bufferdesc.Usage = GL_USAGE_IMMUTABLE;
		break;
	case E_api_Usage_Dynamic:
		bufferdesc.Usage = GL_USAGE_DYNAMIC;
		break;
	case E_api_Usage_Staging:
		bufferdesc.Usage = GL_USAGE_STAGING;
		break;
	default :
		bufferdesc.Usage = GL_USAGE_DEFAULT;
		break;
	}

	GL_SUBRESOURCE_DATA subresourceDesc;
	subresourceDesc.pSysMem = pInitialData->pSysMem;
	subresourceDesc.SysMemPitch = pInitialData->SysMemPitch;
	subresourceDesc.SysMemSlicePitch = pInitialData->SysMemSlicePitch;

	glCreateBuffer(&bufferdesc, &subresourceDesc, &m_id);
}

C_gl_Buffer::~C_gl_Buffer()
{
	glDeleteBuffer(&m_id);
}

void C_gl_Buffer::GetDesc(S_api_BufferDesc * pDesc)
{
	memcpy((void *) pDesc, (void *) &m_Desc, sizeof(m_Desc));
}

bool C_gl_Buffer::Map(E_api_Map MapType, int32 MapFlags, void **ppData)
{
	glBindBuffer(GL_ARRAY_BUFFER, m_id);

	switch (MapType)
	{
	case E_api_Map_Read:		
		*ppData = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY);
		break;
	case E_api_Map_Write:
		*ppData = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
		break;
	case  E_api_Map_Read_Write:
		*ppData = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE);
		break;
	default:
		*ppData = NULL;
		break;
	}		

	glBindBuffer(GL_ARRAY_BUFFER, 0);

	return glCheckError(__LINE__, "C_gl_Buffer.cpp");
}

void C_gl_Buffer::Unmap()
{
	glBindBuffer(GL_ARRAY_BUFFER, m_id);
	glUnmapBuffer(GL_ARRAY_BUFFER);
	glBindBuffer(GL_ARRAY_BUFFER, 0);
}

void * C_gl_Buffer::Get()
{
	return &m_id;
}